/*-----------------------------------------------------------------------------
|                               File description                              |
-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
 * @file      : template.h
 * @author    : TODO:YourName (TODO:yourEmail@xx.com)
 * @brief     : TODO: brief description
 * @version   : v0.0.1
 * @date      : 20xx.xx.xx
 * @note      : Encoding UTF-8 | 1 tab = 4 spaces | 1 line <= 80 characters
 * @license   : TODO:See www.runoob.com/w3cnote/open-source-license.html
 * Copyright (C) 2024 by TODO:YourName. All rights reserved.
-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
|                                 Includes begin                              |
-----------------------------------------------------------------------------*/
#include "template.h"
// FIXME: replace "TEMPLATE" and "template" with your module name
/*-----------------------------------------------------------------------------
|                                 Includes end                                |
-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
|                                 Declare begin                               |
-----------------------------------------------------------------------------*/
/**
 * @brief for template debug
 * @note Add MACRO "-D TEMPLATE_DEBUG" to Compiler Flags enable debug
 */
#ifdef TEMPLATE_DEBUG
/**
 * @brief log information output interface with different levels
 * @param level log level
 * @param format log format
 * @retval int number of characters output
 * @note  If define TEMPLATE_DEBUG, you need to implement this function
 */
__attribute__((weak))
int ex_template_log(int level, const char *format, ...)
{
    /*
    User to implement log function
    ex:
    char log_buf[256];
    va_list args;
    va_start(args, format);
    printf("[LV.%d]", level);
    size_t cnt = vsnprintf(log_buf, sizeof(log_buf), format, args);
    printf("%s", log_buf);
    printf("\n");
    return cnt;
    */
   return 0;
}
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
__attribute__((weak))
void ex_template_assert_failed(const char *file, uint32_t line)
{
    /* User can add his own implementation 
    to report the file name and line number, 
    ex: 
    printf("Wrong parameters value: file %s on line %d\r\n", file, line);
    while(1);
    */
}

#define LOG(level, format, ...) ex_template_log(level, format, ##__VA_ARGS__)
#define TEMPLATE_ASSERT(expr) \
((expr) ? (void)0U : ex_template_assert_failed(__FILE__, __LINE__))
#else
#define LOG(level, format, ...) (void)0
#define TEMPLATE_ASSERT(e)      (void)0
#endif /* TEMPLATE_DEBUG */
#define LOGD(format, ...) LOG(0, format, ##__VA_ARGS__) /* log level debug   */
#define LOGI(format, ...) LOG(1, format, ##__VA_ARGS__) /* log level info    */
#define LOGW(format, ...) LOG(2, format, ##__VA_ARGS__) /* log level warning */
#define LOGE(format, ...) LOG(3, format, ##__VA_ARGS__) /* log level error   */

#define TEMPLATE_FREE(p) do{pTemplate->p_port->pf_free(p);p = NULL;}while(0)
/*-----------------------------------------------------------------------------
|                                 Declare end                                 |
-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
|                          Funciton definition begin                          |
-----------------------------------------------------------------------------*/
/**
 * @brief constructor for template
 * @param template_t template handle
 * @param template_ex_port_t port handle
 * @retval template_status_t OK:TEMPLATE_STATUS_OK
 */
template_status_t template_constructor(template_t *pTemplate,
                                       const template_ex_port_t *pPort)
{
    template_status_t retval = TEMPLATE_STATUS_OK;
    /* check param --------------------------------------*/
    TEMPLATE_ASSERT(NULL != pTemplate);
    TEMPLATE_ASSERT(__CHECK_TEMPLATE_EX_PORT(pPort));
    /* check init status --------------------------------*/
    LOGI("template init start\n");
    if (TEMPLATE_INITED_MAGIC == pTemplate->is_init)
    {
        LOGE("template already inited\n");
        return TEMPLATE_STATUS_INITED;
    }
    /* check resource -----------------------------------*/
    retval = pPort->pf_malloc(TEMPLATE_BUFFER_SIZE,
                                          (void**)&pTemplate->p_buffer);
    if (TEMPLATE_STATUS_OK != retval)
    {
        LOGE("template malloc failed\n");
        return retval;
    }
    /* init ---------------------------------------------*/
    pTemplate->p_port = pPort;
    pTemplate->next = NULL;
    pTemplate->is_init = TEMPLATE_INITED_MAGIC;
    LOGI("template init success\n");
    return retval;
}

/**
 * @brief constructor for template
 * @param template_t template handle
 * @retval template_status_t OK:TEMPLATE_STATUS_OK
 */
template_status_t template_destructor(template_t *pTemplate)
{
    /* check param --------------------------------------*/
    TEMPLATE_ASSERT(NULL != pTemplate);
    /* check init status --------------------------------*/
    LOGI("template destructor start\n");
    if (TEMPLATE_INITED_MAGIC != pTemplate->is_init)
    {
        LOGE("template not inited\n");
        return TEMPLATE_STATUS_NOT_INITED;
    }
    TEMPLATE_FREE(pTemplate->p_buffer);
    pTemplate->is_init = ~TEMPLATE_INITED_MAGIC;
    LOGI("template destructor success\n");
    return TEMPLATE_STATUS_OK;
}


template_status_t template_write(template_t *pTemplate,
                                 uint8_t         *data,
                                 uint16_t         len)
{
    template_status_t retval = TEMPLATE_STATUS_OK;
    /* check param --------------------------------------*/
    TEMPLATE_ASSERT(NULL != pTemplate);
    TEMPLATE_ASSERT(NULL != data);
    TEMPLATE_ASSERT(len > 0);
    /* check init status --------------------------------*/
    LOGI("template write start\n");
    if (TEMPLATE_INITED_MAGIC != pTemplate->is_init)
    {
        LOGE("template not inited\n");
        return TEMPLATE_STATUS_NOT_INITED;
    }
    /* write --------------------------------------------*/
    retval = pTemplate->p_port->pf_write(data, len);
    if (TEMPLATE_STATUS_OK != retval)
    {
        LOGE("template write failed\n");
        return retval;
    }
    LOGI("template write success\n");
    return retval;
}

template_status_t template_read(template_t  *pTemplate,
                                 uint8_t         *data,
                                 uint16_t         len)
{
    template_status_t retval = TEMPLATE_STATUS_OK;
    /* check param --------------------------------------*/
    TEMPLATE_ASSERT(NULL != pTemplate);
    TEMPLATE_ASSERT(NULL != data);
    TEMPLATE_ASSERT(len > 0);
    /* check init status --------------------------------*/
    LOGI("template read start\n");
    if (TEMPLATE_INITED_MAGIC != pTemplate->is_init)
    {
        LOGE("template not inited\n");
        return TEMPLATE_STATUS_NOT_INITED;
    }
    /* read ---------------------------------------------*/
    retval = pTemplate->p_port->pf_read(data, len);
    if (TEMPLATE_STATUS_OK != retval)
    {
        LOGE("template read failed\n");
        return retval;
    }
    LOGI("template read success\n");
    return retval;
}

template_status_t template_ctrl(template_t  *pTemplate,
                                 uint32_t          cmd, 
                                 void          *param)
{
    template_status_t retval = TEMPLATE_STATUS_OK;
    /* check param --------------------------------------*/
    TEMPLATE_ASSERT(NULL != pTemplate);
    /* check init status --------------------------------*/
    LOGI("template ctrl start\n");
    if (TEMPLATE_INITED_MAGIC != pTemplate->is_init)
    {
        LOGE("template not inited\n");
        return TEMPLATE_STATUS_NOT_INITED;
    }
    /* ctrl ---------------------------------------------*/
    LOGI("template ctrl cmd:0x%x,param:%X\n", cmd, param);
    retval = pTemplate->p_port->pf_ctrl(cmd, param);
    if (TEMPLATE_STATUS_OK != retval)
    {
        LOGE("template ctrl failed\n");
        return retval;
    }
    LOGI("template ctrl success\n");
    return retval;
}

/*-----------------------------------------------------------------------------
|                           Funciton definition end                           |
-----------------------------------------------------------------------------*/
